package com.linkstec.redis;

import java.util.Collections;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * 单机版分布式锁，主从会有问题
 * @author 刘路
 *
 */
public class RedisUtilApp2 {

	private static final Logger logger = LogManager.getLogger();

//	private static String keyNameSpace;

	private static JedisPool jedisPool = null;

	private static Jedis jedisForGet = null;

	private static String hostAndPort;
	private static String passwd;

	/**
	 * 获取Jedis实例,单服务器调用模式
	 * 
	 * @return
	 */
	public synchronized static Jedis getJedis() {
		if (null == jedisPool) {
			JedisPoolConfig config = new JedisPoolConfig();
			// 最大连接数
			config.setMaxTotal(100);
			// 最大空闲数
			config.setMaxIdle(20);
			config.setMinIdle(10);
			// 最大等待时间
			config.setMaxWaitMillis(1000);
			// 验证
			config.setTestOnBorrow(true);
			String host = hostAndPort.split(":")[0];
			int port = Integer.valueOf(hostAndPort.split(":")[1]);
			jedisPool = new JedisPool(config, host, port, 10000, passwd);
		}
		int tryTimes = 3;
		while (tryTimes > 0) {
			try {
				tryTimes--;
				jedisForGet = jedisPool.getResource();
				if (jedisForGet != null) {
					break;
				}
			} catch (Exception e) {
				if (tryTimes > 0) {
					continue;
				}
				e.printStackTrace();
				throw new RuntimeException("redis没有连接,请检查redis集群");
			}
		}
		return jedisForGet;
	}

	/**
	 * 释放jedis资源
	 * 
	 * @param jedis
	 */
	public static void returnResource(final Jedis jedis) {
		if (jedis != null) {
			jedis.close();
		}
	}
	
    private static final String LOCK_SUCCESS = "OK";
    private static final String SET_IF_NOT_EXIST = "NX";
    private static final String SET_WITH_EXPIRE_TIME = "PX";

    /**
     * 尝试获取分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @param expireTime 超期时间
     * @return 是否获取成功
     */
    public static boolean tryGetDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) {

        String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);

        if (LOCK_SUCCESS.equals(result)) {
        	logger.info("加锁成功！！！");
            return true;
        }
        return false;

    }
    private static final Long RELEASE_SUCCESS = 1L;
    /**
     * 释放分布式锁
     * @param jedis Redis客户端
     * @param lockKey 锁
     * @param requestId 请求标识
     * @return 是否释放成功
     */
    public static boolean releaseDistributedLock(Jedis jedis, String lockKey, String requestId) {

        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));

        if (RELEASE_SUCCESS.equals(result)) {
            return true;
        }
        return false;

    }
	@SuppressWarnings("rawtypes")
	public static void setConfig(Map cfg) {
		// hostsAndPorts = (String)cfg.get(MotConst.GCK_REDIS_CLUSTER);
//		keyNameSpace = (String) cfg.get("keyNamespace");
		hostAndPort = (String) cfg.get("redisHostAndPortSingle");
	}

	public static void main(String[] args) {
		try {
			// 负载均衡 haproxy+keepalived
//			hostAndPort = "192.168.10.235:1080";
			hostAndPort = "localhost:6379";
			passwd = "foobared";
			Jedis jedis = getJedis();
			boolean getlock = tryGetDistributedLock(jedis, "lockkey", "lockvalue", 20000);
			if (getlock == true) {
				logger.info("加锁成功");
			}
			boolean releaselock = releaseDistributedLock(jedis, "lockkey", "lockvalue");
			if (releaselock == true) {
				logger.info("解锁成功");
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
